package engine;

import java.io.*;
import java.util.*;

import com.managment.functions.activate.*;
import com.managment.functions.add.*;
import com.managment.functions.check.*;
import com.managment.functions.delete.*;
import com.managment.functions.get.*;
import com.managment.functions.update.*;
import com.managment.alarm.AlarmStatus;
import com.managment.alarm.CheckAlarm;
import com.managment.data.*;
import communication.account.login.Login;
import communication.account.login.LoginAccomplished;
import communication.account.login.LoginFailed;

import database.DatabaseConnector;
import java.net.*;

import tasks.TaskThread;

import management.Scheduler;
import microcontroler.MicroControler;

public class HomeUser extends Thread{
    Socket clientSocket;       
    List <HomeUser> U;
    public ObjectOutputStream oos;
    public ObjectInputStream ois;
    Object o;
	private String login = "testowy";
	boolean loged = false;
	private DatabaseConnector dc;	
	private MicroControler mc;
	private Profile active_profile;
	private List<Profile> profiles;
	private List<TaskThread> active_tasks;
	private String password;
	
	
    public HomeUser(Socket clientSocket, List <HomeUser> U, ObjectInputStream in, ObjectOutputStream out, String password,
    				Profile active_profile, List<Profile> profiles, List<TaskThread> active_tasks, DatabaseConnector dc, MicroControler mc){
    	this.clientSocket = clientSocket;
        this.U=U;
        this.ois = in;
        this.oos = out;
        this.dc = dc;
        this.mc = mc;
        this.active_profile = active_profile;
        this.profiles = profiles;
        this.active_tasks = active_tasks;
        this.password = password;
    }
    
    public void removeProfile(String profile){
    	for(int i=0; i<profiles.size(); i++){
    		if(profiles.get(i).getName().equals(profile))
    			profiles.remove(i);
    	}
    	if(active_profile != null){
    		if(active_profile.getName().equals(profile)){
    			System.out.println("Usuwam aktywny profil");
    			active_profile = null;
    			for(int i=0; i < active_tasks.size(); i++){
    				System.out.println("Usuwam aktywny task");
    				active_tasks.set(i, null);
    			}
    		}
    	}
    }

    public Profile findProfile(String name){
    	for(int i=0; i<profiles.size(); i++){
    		if(profiles.get(i).getName().equals(name))
    			return profiles.get(i);
    	}
    	return null;
    }
    
	public void run(){
	    while (true){	
	    	try {
	    		System.out.println("OCZEKUJE NA OBIEKT");
				o = ois.readObject();
				System.out.println("OTRZYMANO OBIEKT: "+o.getClass().toString());
				if(o instanceof Login){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Loguje się");
					System.out.println("OBIEKT(Hasło = "+((Login)o).getPassword()+")");
					System.out.println("===============================================");
					if(((Login)o).getPassword().equals(password)){
						loged = true;
						oos.writeObject(new LoginAccomplished());
						System.out.println(" -Zalogował się");
					}
					else{
						oos.writeObject(new LoginFailed());
						System.out.println(" -Nie udało mu się zalogować");
					}
				}
				else if(o instanceof CheckMedia){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Sprawdza stan medium");
					CheckMedia ocm = ((CheckMedia)o);
					System.out.println("OBIEKT(Media = "+ocm.getMedia().toString()+")");
					System.out.println("===============================================");
					Media media = ((CheckMedia)o).getMedia();
					String s = null;
					microcontroler.State st = mc.getState();
					if(media.equals(Media.BATHROOMLIGHT)){
						System.out.println(" -Sprawdza światło w łazience");
						if(st.isLightBathroom())
							s = "on";
						else
							s = "off";
					}
					else if(media.equals(Media.KITCHENLIGHT)){
						System.out.println(" -Sprawdza światło w kuchni");
						if(st.isLightKitchen())
							s = "on";
						else
							s = "off";
					}
					else if(media.equals(Media.ROOMLIGHT)){
						System.out.println(" -Sprawdza światło w pokoju");
						if(st.isLightRoom())
							s = "on";
						else
							s = "off";
					}
					else if(media.equals(Media.HEATTER)){
						System.out.println(" -Sprawdza temperaturę");
						switch(st.getHeatingLevel()){
						case 1:
							s = "18";
							break;
						case 2:
							s = "20";
							break;
						case 3:
							s = "22";
							break;
						case 4:
							s = "24";
							break;
						default:
							s = "0";
							break;
						}	
					}
					System.out.println(" -STAN: "+s);
					MediaState state = new MediaState();
					state.setState(s);
					System.out.println("Przed wysłaniem");
					oos.writeObject(state);
					oos.flush();
					System.out.println("Wysłano stan medium");
				}
				else if(o instanceof CheckAlarm){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Sprawdza alarm");
					System.out.println("===============================================");
					AlarmStatus as = new AlarmStatus();
					if(mc.getAlarmStatus()){
						System.out.println(" -Alarm włączony");
						as.setStatus("true");
					}
					else{
						System.out.println(" -Alarm wyłączony");
						as.setStatus("false");
					}
					oos.writeObject(as);
				}
				
				else if(o instanceof AddTask){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Dodaje zadanie");
					Task current_task = ((AddTask)o).getTask();
					System.out.println("OBIEKT(ID="+current_task.getId()+", ID Profilu="+current_task.getProfilId()+", Media="+current_task.getMedia().toString()+
									   ", Stan="+current_task.getState()+")");
					System.out.println("===============================================");
					//Utils.printTask(current_task);
					
					//powinno być dodanie oddzielnego tasku do bazy danych, który się odpali kiedyś tam...
					//w razie gdyby serwer padł przy starcie czyta wszystkie taski z bazy
				
					Scheduler.addTask(current_task, mc, oos, false);
				}
				else if(o instanceof ActivateProfile){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Aktywuje profil");
					ActivateProfile oap = (ActivateProfile)o;
					System.out.println("OBIEKT(Nazwa="+oap.getName()+")");
					System.out.println("===============================================");
					if((active_profile = findProfile(((ActivateProfile)o).getName())) != null){
						for(int i=0; i<active_profile.getTasks().size(); i++){
							active_tasks.add(Scheduler.addTask(active_profile.getTasks().get(i), mc, oos, true));
						}
						oos.writeObject(new ProfileActivated());
						System.out.println("Aktywowano profil: "+((ActivateProfile)o).getName());
					}
					else{
						oos.writeObject(new ActivationFailed());
						System.out.println("Nie udało się aktywować profilu: "+((ActivateProfile)o).getName());
					}
						
				}
				
				else if(o instanceof AddProfile){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Dodaje profil");
					AddProfile oap = (AddProfile)o;
					System.out.println("OBIEKT(Nazwa profilu="+oap.getProfile().getName()+")");
					for(int i=0; i < oap.getProfile().getTasks().size(); i++){
						System.out.println("Task(ID="+oap.getProfile().getTasks().get(i).getId()+", ID Profilu="+oap.getProfile().getTasks().get(i).getProfilId()+
								", Media="+oap.getProfile().getTasks().get(i).getMedia().toString()+", Stan="+oap.getProfile().getTasks().get(i).getState()+")");
					}
					System.out.println("===============================================");
					if(dc.addProfil(((AddProfile)o).getProfile())){
						profiles.add(((AddProfile)o).getProfile());
						oos.writeObject(new ProfileAdded());
						System.out.println("Dodano profil: "+((AddProfile)o).getProfile().getName());
					}
					else{
						oos.writeObject(new AddFailed());
						System.out.println("Nie udało się dodać profilu: "+((AddProfile)o).getProfile().getName());
					}
				}
				else if(o instanceof DeleteProfile){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Usuwa profil");
					DeleteProfile odp = (DeleteProfile)o;
					System.out.println("OBIEKT(Nazwa Profilu="+odp.getName()+")");
					System.out.println("===============================================");
					if(dc.deleteProfil(((DeleteProfile)o).getName())){
						removeProfile(((DeleteProfile)o).getName());
						oos.writeObject(new ProfileDeleted());
						System.out.println("Usunięto profil: "+((DeleteProfile)o).getName());
					}
					else{
						oos.writeObject(new DeleteFailed());
						System.out.println("Nie udało się usunąć profilu: "+((DeleteProfile)o).getName());
					}
				}
				else if(o instanceof UpdateProfile){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Modyfikuje profil");
					UpdateProfile oup = (UpdateProfile)o;
					System.out.println("OBIEKT(Nazwa Starego Profilu="+oup.getOldProfile()+")");
					System.out.println("OBIEKT(Nazwa Nowego profilu="+oup.getNewProfile().getName()+")");
					for(int i=0; i < oup.getNewProfile().getTasks().size(); i++){
						System.out.println("Task(ID="+oup.getNewProfile().getTasks().get(i).getId()+", ID Profilu="+oup.getNewProfile().getTasks().get(i).getProfilId()+
								", Media="+oup.getNewProfile().getTasks().get(i).getMedia().toString()+", Stan="+oup.getNewProfile().getTasks().get(i).getState()+")");
					}
					System.out.println("===============================================");
					if(dc.deleteProfil(((UpdateProfile)o).getOldProfile())){
						String active = null;
						if(active_profile.getName().equals(((UpdateProfile)o).getOldProfile()))
							active = active_profile.getName();
						removeProfile(((UpdateProfile)o).getOldProfile());
						System.out.println("Usunięto stary profil: "+((UpdateProfile)o).getOldProfile());
						if(dc.addProfil(((UpdateProfile)o).getNewProfile())){
							profiles.add(((UpdateProfile)o).getNewProfile());
							if(active != null){
								active_profile = ((UpdateProfile)o).getNewProfile();
								for(int i=0; i<active_profile.getTasks().size(); i++){
									active_tasks.add(Scheduler.addTask(active_profile.getTasks().get(i), mc, oos, true));
								}
							}
							oos.writeObject(new ProfileUpdated());
							System.out.println("Zmodyfikowano profil: "+((UpdateProfile)o).getNewProfile().getName());
						}
						else{
							oos.writeObject(new UpdateFailed());
							System.out.println("Nie udało się dodać nowego profilu: "+((AddProfile)o).getProfile().getName());
						}
						
					}
					else{
						oos.writeObject(new UpdateFailed());
						System.out.println("Nie udało się usunąć starego profilu: "+((UpdateProfile)o).getOldProfile());
					}
				}
				else if(o instanceof GetProfiles){
					System.out.println("===============================================");
					System.out.println(" @"+Utils.getSysTime()+" -> "+clientSocket.getInetAddress().getHostAddress()+ " Pobiera profile");
					GetProfiles ogp = (GetProfiles)o;
					System.out.println("OBIEKT( )");
					System.out.println("===============================================");
					List<Profile> p;
					if((p = dc.getProfils()) != null){
						System.out.println(" -Znaleziono "+p.size()+" profili");
						for(int i=0; i < p.size(); i++){
							System.out.println("Profil: "+p.get(i).getName());
							if(active_profile != null && active_profile.getName() != null){
								if(p.get(i).getName().equals(active_profile.getName())){
									System.out.println("Ustawiam aktywny profil");
									p.get(i).setActive(true);
									break;
								}
							}
						}
						Profiles profiles = new Profiles();
						profiles.setProfiles(p);
						System.out.println("Przed wysłaniem obiektu");
						oos.writeObject(profiles);
						System.out.println("Pobrano profile");
					}
					else{
						oos.writeObject(new GetFailed());
						System.out.println("Nie udało się pobrać profili");
					}
				}
			} catch (IOException e) {
				stop();
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				stop();
				e.printStackTrace();
			}
	    }
	}
}	    		